require 'rubygems'
require 'sinatra/base'
require 'fileutils'
require 'json'
require 'parseconfig'
require 'logger'

class Installr::Server::Runner < Sinatra::Base

puts "Installr agent version #{Installr::VERSION} starting ..."
puts "Copyright (C) 2012 by InnoDS"

# start of provisioing
  config = ParseConfig.new(File.expand_path('../../../conf/Installr.conf', __FILE__))
   unless config
     puts "[main:provisioning] cannot find the configuration file Installr.conf"
     exit(-1)
   end

   agent_port = config['agent_port']
   agent_port = '4567' unless agent_port
   set :port, agent_port.to_i
# end of provisioing

  def initialize
    super
    @options = { :verbose => false }
    config = ParseConfig.new(File.expand_path('../../../conf/Installr.conf', __FILE__))

    if config['verbose'] == 'true'
      @options[:verbose] = true
    else
      @options[:verbose] = false
    end

    @options[:debug] = config['debug']
    @options[:agent_port] = config['agent_port']
    @options[:manager_port] = config['manager_port']
    @options[:manager_user] = config['manager_user']
    @options[:manager_password] = config['manager_password']
    @options[:manager_timeout] = config['manager_timeout']
    @options[:data_base_dir] = config['data_base_dir']
    @options[:log_base_dir] = config['log_base_dir']
    @options[:tomcat_base_dir] = config['tomcat_base_dir']
    @options[:log] = config['log']
    @options[:access_log] = config['access_log']
    @options[:access_list] = config['access_list']

    # default value setting if unavailable
    @options[:debug] = 2 unless @options[:debug]
    @options[:agent_port] = '4567' unless @options[:agent_port]
    @options[:data_base_dir] = File.expand_path(ENV['HOME'] + '/Installr/data') unless @options[:data_base_dir]
    @options[:log_base_dir] = File.expand_path(ENV['HOME'] + '/Installr/logs') unless @options[:log_base_dir]
    @options[:tomcat_base_dir] = File.expand_path(ENV['CATALINA_HOME']) unless @options[:tomcat_base_dir]
    @options[:log] = "InstallrAgent.log" unless @options[:log]
    @options[:access_log] = "InstallrAgent_access.log" unless @options[:access_log]
    @options[:access_list] = "hosts.allow" unless @options[:access_list]

    FileUtils.mkdir_p(@options[:log_base_dir]) unless File.directory?(@options[:log_base_dir])
    logfile = @options[:log_base_dir] + '/' + @options[:log]
    access_logfile = @options[:log_base_dir]+ '/' + @options[:access_log]
    @log = Logger.new(logfile, 'daily')
    case @options[:debug]
      when 1 then @log.level = Logger::FATAL
      when 2 then @log.level = Logger::ERROR
      when 3 then @log.level = Logger::INFO
      when 4 then @log.level = Logger::UNKNOWN
      when 5 then @log.level = Logger::WARN
      when 6 then @log.level = Logger::DEBUG
      else @log.level = Logger::DEBUG
    end

    @access_log = Logger.new(access_logfile, 'daily')
    @access_log.level = Logger::INFO

    @access_list = File.expand_path('../../../conf/' + @options[:access_list], __FILE__)
    @white_list = []
    if File.exist?(@access_list)
      file = File.new(@access_list, "r")
      file.each_line do
        |line|
        @white_list << line
      end
    else
      puts "[main:initialize] cannot find the access list file #{@access_list}"
      @log.error("[main:initialize] cannot find the access list file #{@access_list}")
      exit(-1)
    end

    if @white_list == []
      puts "[main:initialize] empty access_list in #{@access_list}"
      @log.error "[main:initialize] empty access_list in #{@access_list}"
      exit(-1)
    end
    
    @storage = Installr::Database::Storage.new(@log, @options)
    @storage.open
    @manager = Installr::Manager::Tomcat.new(@log, @options)
  end

  before /.*/ do
    content_type :json

    check_request_ip = false
    @white_list.each do
      |white_ip|
      check_request_ip = true if request.ip == white_ip.strip
    end

    if check_request_ip
      @access_log.info "#{request.ip}  \"#{request.url}\""
    else
      puts "[authentication] #{request.ip} ---> 401 Unauthorized: check the security policy!"
      @access_log.error("[authentication] #{request.ip} ---> 401 Unauthorized: check the security policy!")
      halt 401, "[authentication] check the security policy!"
    end
  end

  post '/app/deploy' do
    @access_log.info "  ---> #{params.inspect}"
    args = []
    args << params[:app_name]
    args << params[:war_file]
    args << params[:hexdigest]
    args << params[:remote_file_path]
    result = Installr::Server::Command.const_get("app".capitalize).new(@manager, @storage, @log, @options).send(:deploy, *args.collect(&:dup))
    case result
      when -1
        deploy_result = [ { :result => "the same version of app #{params[:app_name]} is already deployed" } ]
      when 0
        deploy_result = [ { :result => "Successfully deployed" } ]
    end
    deploy_result.to_json
  end

  post '/app/undeploy' do
    @access_log.info "  ---> #{params.inspect}"
    args = []
    args << params[:app_name]
    result = Installr::Server::Command.const_get("app".capitalize).new(@manager, @storage, @log, @options).send(:undeploy, *args.collect(&:dup))
    case result
      when -1
        deploy_result = [ { :result => "cannot find app #{params[:app_name]}" } ]
      when 0
        deploy_result = [ { :result => "Successfully undeployed" } ]
    end
    deploy_result.to_json
  end

  post '/app/activate' do
    @access_log.info "  ---> #{params.inspect}"
    args = []
    args << params[:app_name]
    args << params[:hexdigest]
    result = Installr::Server::Command.const_get("app".capitalize).new(@manager, @storage, @log, @options).send(:activate, *args.collect(&:dup))
    deploy_result = [ { :result => result } ]
    deploy_result.to_json
  end

  post '/app/deactivate' do
    @access_log.info "  ---> #{params.inspect}"
    args = []
    args << params[:app_name]
    result = Installr::Server::Command.const_get("app".capitalize).new(@manager, @storage, @log, @options).send(:deactivate, *args.collect(&:dup))
    deploy_result = [ { :result => result } ]
    deploy_result.to_json
  end

  post '/app/start' do
    @access_log.info "  ---> #{params.inspect}"
    args = []
    args << params[:app_name]
    result = Installr::Server::Command.const_get("app".capitalize).new(@manager, @storage, @log, @options).send(:start, *args.collect(&:dup))
    deploy_result = [ { :result => result } ]
    deploy_result.to_json
  end

  post '/app/stop' do
    @access_log.info "  ---> #{params.inspect}"
    args = []
    args << params[:app_name]
    result = Installr::Server::Command.const_get("app".capitalize).new(@manager, @storage, @log, @options).send(:stop, *args.collect(&:dup))
    deploy_result = [ { :result => result } ]
    deploy_result.to_json
  end

  get '/app/info/:app_name' do
    args = []
    args << params[:app_name]
    result = Installr::Server::Command.const_get("app".capitalize).new(@manager, @storage, @log, @options).send(:info, *args.collect(&:dup))
    deploy_result = [ { :result => result } ]
    deploy_result.to_json
  end

  post '/app/head' do
    @access_log.info "  ---> #{params.inspect}"
    args = []
    args << params[:app_name]
    args << params[:app_md5hash]
    result = Installr::Server::Command.const_get("app".capitalize).new(@manager, @storage, @log, @options).send(:head, *args.collect(&:dup))
    case result
      when 0
        deploy_result = [ { :result => "Successfully changed" } ]
      else -1
        deploy_result = [ { :result => "Failed" } ]
    end
    
    deploy_result.to_json
  end

  get '/app/history/:app_name' do
    args = []
    args << params[:app_name]
    result = Installr::Server::Command.const_get("app".capitalize).new(@manager, @storage, @log, @options).send(:history, *args.collect(&:dup))
    deploy_result = [ { :result => result } ]
    deploy_result.to_json
  end

  get '/system/info/all' do
    args = []
    status = Installr::Server::Command.const_get("system".capitalize).new(@manager, @storage, @log, @options).send(:info_all, *args.collect(&:dup))
    list = Installr::Server::Command.const_get("system".capitalize).new(@manager, @storage, @log, @options).send(:info_list, *args.collect(&:dup))
    deploy_result = [ { :status => status, :list => list } ]
    deploy_result.to_json
  end

  post '/system/log' do
    @access_log.info "  ---> #{params.inspect}"
    args = []
    args << params[:remote_log_file]
    args << params[:remote_log_length]
    result = Installr::Server::Command.const_get("system".capitalize).new(@manager, @storage, @log, @options).send(:log, *args.collect(&:dup))
    deploy_result = [ { :result => result } ]
    deploy_result.to_json
  end

  post '/self/log' do
    @access_log.info "  ---> #{params.inspect}"
    args = []
    args << params[:remote_log_file]
    args << params[:remote_log_length]
    result = Installr::Server::Command.const_get("self".capitalize).new(@manager, @storage, @log, @options).send(:log, *args.collect(&:dup))
    deploy_result = [ { :result => result } ]
    deploy_result.to_json
  end
end
